iOS 包瘦身浅析

为什么要做包瘦身?

Your app’s total uncompressed size must be less than 4 billion bytes. Each Mach-O executable file (for example, app_name.app/app_name) must not exceed these limits:

For apps whose MinimumOSVersion is less than 7.0: maximum of 80 MB for the total of all __TEXT sections in the binary.

For apps whose MinimumOSVersion is 7.x through 8.x: maximum of 60 MB per slice for the __TEXT section of each architecture slice in the binary.

For apps whose MinimumOSVersion is 9.0 or greater: maximum of 400 MB for the size of the Mach-O binary file.

Apple 对上架App 是有包大小限制的。超过这个限制,是无法提交审核的。

However, consider download times when determining your app’s size. Minimize the file’s size as much as possible, keeping in mind that there is a 100 MB limit for over-the-air downloads.

尽可能控制包大小, 超过100MB的App 是不会被自动更新到用户手机上

如何分析可执行文件的大小

AppStore 上传的包大小 = 资源文件大小 + 可执行文件大小

资源文件大小 显而易见。 但可执行文件由 具体的(.h/.m/.swift)文件编译链接而成。这个光是看代码文件大小是衡量不出来的。

这个时候就要介绍一下LinkMap了。 Xcode的LinkMap文件。LinkMap文件是Xcode产生可执行文件的同时生成的链接信息,用来描述可执行文件的构造成分,包括代码段__TEXT和数据段__DATA的分布情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Sections:
# Address Size Segment Section
0x100002680 0x02DAED20 __TEXT __text
0x102DB13A0 0x00002FAC __TEXT __stubs
0x102DB434C 0x00004DC2 __TEXT __stub_helper
0x102DB9110 0x00172C10 __TEXT __gcc_except_tab
0x102F2BD20 0x001DC91A __TEXT __objc_methname
0x10310863A 0x00039CC2 __TEXT __objc_classname
0x1031422FC 0x00057D8E __TEXT __objc_methtype
0x10319A090 0x00229C39 __TEXT __cstring
0x1033C3CD0 0x00025194 __TEXT __ustring
0x1033E8E80 0x000CC108 __TEXT __const
0x1034B4F88 0x000002C0 __TEXT __swift2_proto
0x1034B5248 0x000003E6 __TEXT __entitlements
0x1034B5630 0x00099AC8 __TEXT __unwind_info
0x10354F0F8 0x000AAED0 __TEXT __eh_frame
0x1035FA000 0x00000010 __DATA __nl_symbol_ptr
0x1035FA010 0x00002558 __DATA __got
0x1035FC568 0x00003F90 __DATA __la_symbol_ptr
0x1036004F8 0x000002E0 __DATA __mod_init_func
0x1036007E0 0x00103990 __DATA __const
0x103704170 0x00123460 __DATA __cfstring
0x1038275D0 0x00012130 __DATA __objc_classlist
0x103839700 0x00000328 __DATA __objc_nlclslist
0x103839A28 0x000016A8 __DATA __objc_catlist
0x10383B0D0 0x00000128 __DATA __objc_nlcatlist
0x10383B1F8 0x00002B68 __DATA __objc_protolist
0x10383DD60 0x00000008 __DATA __objc_imageinfo
0x10383DD68 0x009AECA8 __DATA __objc_const
0x1041ECA10 0x00074B98 __DATA __objc_selrefs
0x1042615A8 0x00000A60 __DATA __objc_protorefs
0x104262008 0x0000EFE8 __DATA __objc_classrefs
0x104270FF0 0x0000B490 __DATA __objc_superrefs
0x10427C480 0x00050BD0 __DATA __objc_ivar
0x1042CD050 0x000B6010 __DATA __objc_data
0x104383060 0x000C0CA0 __DATA __data
0x104443D00 0x00143220 __DATA __common
0x104586F40 0x0013DAC0 __DATA __bss

可执行文件大小 = 末位地址(0x104586F40) + size(0x0013DAC0) - 起始地址(0x100002680)。 注意是16进制

详细的 LinkMap 是 这么几部分组成:

  1. Object files 所编译项目中的所有.obj文件及文件编号

  2. Sections 可执行文件的段表,描述各个段在可执行文件中的偏移位置和大小

  3. Symbols 详细描述各个.obj文件在段表中的分布情况。 可以计算出每个obj文件的占用大小,进而算出每个静态库、功能模块代码占用大小。

官方 Q&A